/*
 * Copyright (c) 2007-2020 西安交通信息投资营运有限公司 版权所有
 */

package com.xci.edu.core.service;

import com.github.lvyanyang.annotation.BindingOperateUser;
import com.github.lvyanyang.annotation.OperateLog;
import com.github.lvyanyang.core.BoolResult;
import com.github.lvyanyang.core.PageList;
import com.github.lvyanyang.core.XCI;
import com.github.lvyanyang.sys.core.BaseSysService;
import com.xci.edu.core.dao.EduQuestionDao;
import com.xci.edu.core.entity.EduQuestion;
import com.xci.edu.core.entity.ExamPaper;
import com.xci.edu.core.entity.ExerciseQuestion;
import com.xci.edu.core.filter.EduQuestionFilter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 试题库服务
 * @author 马星俊 maxingjun@xci96716.com
 * @since 2020-11-25 10:03:01
 */
@Service
public class EduQuestionService extends BaseSysService {
    /** 试题库数据层对象 */
    @Resource private EduQuestionDao eduQuestionDao;

    /**
     * 新建试题库
     * @param entity 试题库实体
     */
    @BindingOperateUser
    @OperateLog(msg = "新建试题库", module = "试题库")
    @Transactional(rollbackFor = Exception.class)
    public BoolResult insert(EduQuestion entity) {
        return save(entity, true);
    }

    /**
     * 修改试题库
     * @param entity 试题库实体
     */
    @BindingOperateUser
    @OperateLog(msg = "修改试题库", module = "试题库")
    @Transactional(rollbackFor = Exception.class)
    public BoolResult update(EduQuestion entity) {
        return save(entity, false);
    }

    /**
     * 修改试题库状态
     * @param ids    试题库主键字符串
     * @param status 试题库状态
     */
    @OperateLog(msg = "修改试题库状态", module = "试题库")
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(@NotBlank(message = "请指定试题库主键字符串") String ids, @NotNull(message = "请指定试题库状态") Boolean status) {
        XCI.forEachIds(ids, id -> {
            eduQuestionDao.updateStatus(id, status);
        });
    }


    /**
     * 删除试题库
     * @param ids 试题库主键字符串
     */
    @OperateLog(msg = "删除试题库", module = "试题库")
    @Transactional(rollbackFor = Exception.class)
    public BoolResult delete(@NotBlank(message = "请指定试题库主键字符串") String ids) {
        XCI.forEachIds(ids, id -> {
            var entity = eduQuestionDao.selectById(id);
            if (entity == null) return;

            eduQuestionDao.deleteById(entity.getId());
            logService.saveDeleteHistoryLogAsync(entity.getId(), entity);
        });
        return BoolResult.success();
    }

    /**
     * 随机生成试题
     * @param paper 试卷实体对象
     * @return 返回试题库列表
     */
    public List<EduQuestion> randomList(ExamPaper paper) {
        List<EduQuestion> questionList = new ArrayList<>();
        //添加单选题
        if(paper.getAutoRadioCount()>0) {
            questionList.addAll(getRandom(selectListByType(paper.getEduCategoryId(), 1), paper.getAutoRadioCount()));
        }
        //添加多选题
        if(paper.getAutoCheckboxCount()>0) {
        questionList.addAll(getRandom(selectListByType(paper.getEduCategoryId(),1),paper.getAutoRadioCount()));
        }
        //添加判断题
        if(paper.getAutoYesnoCount()>0) {
            questionList.addAll(getRandom(selectListByType(paper.getEduCategoryId(),1),paper.getAutoRadioCount()));
        }
        return questionList;
    }

    /**
     * 根据主键查询单个试题库
     * @param id 试题库主键
     * @return 返回试题库实体
     */
    public EduQuestion selectById(@NotNull(message = "请指定试题库主键") Long id) {
        return eduQuestionDao.selectById(id);
    }

    /**
     * 按科目及试题类型查询试题库列表
     * @param eduCategoryId 科目主键
     * @param questionCategory 试题类型[1-单选题, 2-多选题, 3-判断题]
     * @return 返回试题库列表
     */
    public List<EduQuestion> selectListByType(Long eduCategoryId,Integer questionCategory) {
        return eduQuestionDao.selectListByType(eduCategoryId,questionCategory);
    }

    /**
     * 根据科目id和问题类型获取习题
     * @param eduCategoryId 科目id
     * @param questionCategory 问题类型
     * @return 返回试题库列表
     */
    public List<ExerciseQuestion> getExerciseQuestions(Long eduCategoryId, Integer questionCategory) {
        return eduQuestionDao.getExerciseQuestions(eduCategoryId,questionCategory);
    }

    /**
     * 根据科目id和问题类型获取习题
     * @param studentId 学员id
     * @param favoriteType 收藏类型
     * @return 返回试题库列表
     */
    public List<EduQuestion> getQuestionsByStudentIdAndFavoriteType(Long studentId, int favoriteType) {
        return eduQuestionDao.getQuestionsByStudentIdAndFavoriteType(studentId,favoriteType);
    }

    /**
     * 查询试题库列表
     * @param filter 过滤条件
     * @return 返回试题库列表
     */
    public List<EduQuestion> selectList(EduQuestionFilter filter) {
        return eduQuestionDao.selectList(filter);
    }

    /**
     * 查询试题库分页列表
     * @param filter 过滤条件
     * @return 返回试题库分页列表
     */
    public PageList<EduQuestion> selectPageList(EduQuestionFilter filter) {
        return PageList.of(eduQuestionDao.selectPageList(filter));
    }

    /**
     * 保存数据,在insert和update之前和之后的校验和处理
     * @param entity  试题库实体
     * @param created 是否新建
     */
    private BoolResult save(EduQuestion entity, boolean created) {
        //新建时如果主键未指定,自动设置主键
        XCI.ifTrueAction(XCI.invalidId(entity.getId(), created), () -> entity.setId(XCI.nextId()));

        //更新数据库
        if (created) {
            eduQuestionDao.insert(entity);
            logService.saveInsertHistoryLogAsync(entity.getId(), entity);
        } else {
            var before = eduQuestionDao.selectById(entity.getId());
            eduQuestionDao.update(entity);
            logService.saveUpdateHistoryLogAsync(entity.getId(), before, entity);
        }
        return BoolResult.success();
    }

    //抽取试题
    private List<EduQuestion> getRandom(List<EduQuestion> questionList,int count){
        List backList = null;
        backList = new ArrayList<EduQuestion>();
        Random random = new Random();
        int backSum = 0;
        if (questionList.size() >= count) {
            backSum = count;
        }else {
            backSum = questionList.size();
        }
        for (int i = 0; i < backSum; i++) {
            int index = random.nextInt(questionList.size());
            backList.add(questionList.get(index));
            questionList.remove(index);
        }
        return backList;
    }

}